//! 数据包格式

use crate::consts::*;
use crate::id::*;
use heapless::Vec;

/// 版本号
pub(crate) const VERSION: u8 = 0x03;
/// 数据包最小长度(数据长度为0)
pub const MIN_LEN: usize = 10;

/// 数据包字段相对位置
pub enum Field {
    Version = 0,
    Sn = 1,
    Src = 2,
    Dst,
    Ttl,
    Protocol,
    Data,
}

/// 数据包
#[derive(Default)]
pub struct Packet {
    /// 版本号
    pub version: u8,
    /// 序列号
    pub sn: u8,
    /// 源地址
    pub src: Id,
    /// 目标地址
    pub dst: Id,
    /// 生存时间
    pub ttl: u8,
    /// 协议类型
    pub protocol: u8,
    /// 数据
    pub data: Vec<u8, DataLen>,
}
impl Packet {
    /// 创建一个最小长度的数据包
    pub fn new() -> Self {
        let packet = Packet::default();
        return packet;
    }
    /// 设置字段内容
    pub fn set_var(&mut self, field: Field, buf: &[u8]) -> bool {
        match field {
            Field::Version => {
                self.version = buf[0];
            }
            Field::Sn => {
                self.sn = buf[0];
            }
            Field::Src => {
                self.src = buf.into();
            }
            Field::Dst => {
                self.dst = buf.into();
            }
            Field::Ttl => {
                self.ttl = buf[0];
            }
            Field::Protocol => {
                self.protocol = buf[0];
            }
            Field::Data => {
                if (buf.len() as isize + Field::Data as isize) as usize > DATA_LEN {
                    return false;
                }
                // 设置负载
                self.data = Vec::from_slice(buf).unwrap();
            }
        }
        return true;
    }
    /// 获取数据包的字节流
    pub fn to_buf(&self) -> Vec<u8, PacketLen> {
        let mut buf: Vec<u8, PacketLen> = Vec::from_slice(&[VERSION]).unwrap();
        buf.push(self.sn).unwrap();
        buf.extend_from_slice(&self.src).unwrap();
        buf.extend_from_slice(&self.dst).unwrap();
        buf.push(self.ttl).unwrap();
        buf.push(self.protocol).unwrap();
        buf.extend_from_slice(&self.data).unwrap();
        return buf;
    }
    /// 尝试从字节流转为数据包
    pub fn try_from_buf(buf: &[u8]) -> Result<Self, &'static str> {
        let buf_len = buf.len();
        if buf_len < MIN_LEN {
            return Err("Packet buf too short.");
        } else if buf_len > PACKET_LEN {
            return Err("Packet buf too long.");
        }

        if buf[Field::Version as usize] == VERSION {
            let mut pkt = Packet::default();
            pkt.version = VERSION;
            pkt.sn = buf[Field::Sn as usize];
            let buf = &buf[Field::Src as usize..];
            let (src, buf) = buf.split_at(((buf[0] & 0x0F) + OFFSET) as usize);
            pkt.src = src.into();
            let (dst, buf) = buf.split_at(((buf[0] & 0x0F) + OFFSET) as usize);
            pkt.dst = dst.into();
            pkt.ttl = buf[0];
            pkt.protocol = buf[1];
            pkt.data = Vec::from_slice(&buf[2..]).unwrap();
            return Ok(pkt);
        } else {
            return Err("Packet no version.");
        }
    }
}
